package com.jhj.common.util;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;

public class FtpUtil {
    
    public static Log ftpLog = LogFactory.getLog("FTP");
    
    /** ThreadLocal的ftpClient对象 */
    private static ThreadLocal<FTPClient> ftpClient = new ThreadLocal<FTPClient>();
    
    /** 文件处理对象 */
    private JhjFileOperator fileOperator = JhjFileOperator.getInstance();
    
    /** FTP 登录用户名 */
    private String userName;
    
    /** FTP 登录密码 */
    private String password;
    
    /** FTP 服务器地址IP地址 */
    private String ip;
    
    /**  FTP 端口 */
    private int port;
    
    /** 上传路径 */
    private String uploadurl = "";
    
    
    /**
     * 获取FTPClient对象
     * 
     * @return
     */
    private FTPClient getFtpClient(String... middleDir) {
        FTPClient fc = ftpClient.get();
        if (fc == null || !fc.isConnected()) {
            int reply;
            try {
                fc = new FTPClient();
                fc.setControlEncoding("UTF-8");
                fc.configure(getFtpConfig());
                fc.connect(ip);
                fc.login(userName, password);
                fc.setDefaultPort(port);
                fc.getReplyString();
                reply = fc.getReplyCode();
                fc.setDataTimeout(120000);
                fc.setConnectTimeout(60000);
                
                if (!FTPReply.isPositiveCompletion(reply)) {
                    fc.disconnect();
                    ftpLog.error("FTP 服务拒绝连接!");
                }
                
                ftpClient.set(fc);
                
                String dir = middleDir.length > 0 ? uploadurl + "/" + middleDir[0] : uploadurl;
                if (!fc.changeWorkingDirectory(dir)) {
                    if (middleDir.length > 0) {
                        String middleDirTmp = middleDir[0].endsWith("/") ? 
                                JhjStringUtil.removeEnd(middleDir[0], "/") : 
                                    middleDir[0];
                        String[] middleDirList = middleDirTmp.split("/");
                        
                        String levelDir = uploadurl;
                        for (String subDir : middleDirList) {
                            
                            levelDir = levelDir + "/" + subDir;
                            if (!fc.changeWorkingDirectory(levelDir)) {
                                if (fc.makeDirectory(levelDir))
                                    fc.changeWorkingDirectory(levelDir);
                            }
                        }
                    }
                }
            } catch (SocketException e) {
                ftpLog.error("登录ftp服务器 " + ip + " 失败,连接超时!");
            } catch (IOException e) {
                ftpLog.error("登录ftp服务器 " + ip + " 失败，FTP服务器无法打开!");
            }
        }
        
        return fc;
    }
    
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    public void setIp(String ip) {
        this.ip = ip;
    }
    
    public void setPort(int port) {
        this.port = port;
    }
    
    public void setUploadurl(String uploadurl) {
        this.uploadurl = uploadurl;
    }
    
    /**
     * 上传单个文件，并重命名
     * 
     * @param fileName--本地文件命
     * @param middleDir--扩展中间路径
     * @return true 上传成功，false 上传失败
     */
    public boolean uploadFile(String fileName, InputStream input, String... middleDir) {
        boolean flag = true;
        try {
            FTPClient fc = getFtpClient(middleDir);
            fc.setFileType(FTP.BINARY_FILE_TYPE);
            fc.enterLocalPassiveMode();
            fc.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
            flag = fc.storeFile(fileName, input);
        } catch (Exception e) {
            flag = false;
            closeConnect();
            ftpLog.error("上传文件失败", e);
        } 
        
        return flag;
    }
    
    /**
     * 下载文件
     * 
     * @param remoteFileName --服务器上的文件名
     * @param localFileName--本地文件名
     * @return true 下载成功，false 下载失败
     */
    public boolean loadFile(String remoteFileName, String localFileName) {
        boolean flag = true;
        FTPClient fc = getFtpClient();
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        try {
            fos = new FileOutputStream(localFileName);
            bos = new BufferedOutputStream(fos);
            flag = fc.retrieveFile(remoteFileName, bos);
        } catch (Exception e) {
            flag = false;
            ftpLog.error("本地文件下载失败!", e);
            closeConnect();
        } finally {
            fileOperator.closeResources(fos, bos);
        }
        
        return flag;
    }
    
    /**
     * 删除一个文件
     */
    public boolean deleteFile(String filename, String... middleDir) {
        boolean flag = true;
        try {
            FTPClient fc = getFtpClient(middleDir);
            flag = fc.deleteFile(filename);
            if (flag) {
                System.out.println("删除文件成功!");
            } else {
                System.out.println("删除文件失败!");
            }
        } catch (Exception e) {
            flag = false;
            ftpLog.error("删除文件失败!!!", e);
            closeConnect();
        }
        
        return flag;
    }
    
    /**
     * 删除目录
     */
    public void deleteDirectory(String pathname) {
        try {
            FTPClient fc = getFtpClient();
            File file = new File(pathname);
            if (file.isDirectory()) {
                file.listFiles();
            } else {
                deleteFile(pathname);
            }
            fc.removeDirectory(pathname);
        } catch (IOException e) {
            ftpLog.error("删除目录失败!!!", e);
        }
    }
    
    /**
     * 删除空目录
     */
    public void deleteEmptyDirectory(String pathname) {
        try {
            FTPClient fc = getFtpClient();
            fc.removeDirectory(pathname);
        } catch (IOException e) {
            ftpLog.error("删除空目录失败!!!", e);
        }
    }
    
    /**
     * 列出服务器上文件和目录
     * 
     * @param regStr --匹配的正则表达式
     */
    public String[] listRemoteFiles(String regStr) {
        String files[] = null;
        FTPClient fc = getFtpClient();
        try {
            files = fc.listNames(regStr);
            if (files == null || files.length == 0)
                ftpLog.info("没有任何文件!");
            else {
                for (int i = 0; i < files.length; i++) {
                    ftpLog.info(files[i]);
                }
            }
        } catch (Exception e) {
            ftpLog.error("列出文件名失败!!!", e);
        }
        
        return files;
    }
    
    /**
     * 列出Ftp服务器上的所有文件和目录
     */
    public String[] listRemoteAllFiles() {
        String names[] = null;
        FTPClient fc = getFtpClient();
        try {
            names = fc.listNames();
            for (int i = 0; i < names.length; i++) {
                System.out.println(names[i]);
            }
        } catch (Exception e) {
            ftpLog.error("列出文件和目录失败!!!", e);
        }
        
        return names;
    }
    
    /**
     * 关闭连接
     */
    public void closeConnect() {
        FTPClient fc = ftpClient.get();
        try {
            if (fc != null && fc.isConnected()) {
                fc.logout();
                fc.disconnect();
            }
        } catch (Exception e) {
            ftpLog.error("关闭连接错误", e);
        }
    }
    
    /**
     * 进入到服务器的某个目录下
     * 
     * @param directory
     */
    public void changeWorkingDirectory(String directory) {
        FTPClient fc = ftpClient.get();
        try {
            fc.changeWorkingDirectory(directory);
        } catch (IOException e) {
            ftpLog.error("进入到服务器的目录失败!!!", e);
        }
    }
    
    /**
     * 返回到上一层目录
     */
    public void changeToParentDirectory() {
        FTPClient fc = ftpClient.get();
        try {
            fc.changeToParentDirectory();
        } catch (IOException e) {
            ftpLog.error("返回到上一层目录失败!!!", e);
        }
    }
    
    /**
     * 重命名文件
     * 
     * @param oldFileName --原文件名
     * @param newFileName --新文件名
     */
    public void renameFile(String oldFileName, String newFileName) {
        FTPClient fc = ftpClient.get();
        try {
            fc.rename(oldFileName, newFileName);
        } catch (IOException e) {
            ftpLog.error("重命名文件失败!!!", e);
        }
    }
    
    /**
     * 设置FTP客服端的配置--一般可以不设置
     * 
     * @return ftpConfig
     */
    private FTPClientConfig getFtpConfig() {
        FTPClientConfig ftpConfig = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
        ftpConfig.setServerLanguageCode(FTP.DEFAULT_CONTROL_ENCODING);
        return ftpConfig;
    }
    
    /**
     * 在服务器上创建一个文件夹
     * 
     * @param dir 文件夹名称，不能含有特殊字符，如 \ 、/ 、: 、* 、?、 "、 <、>...
     */
    public boolean makeDirectory(String dir) {
        FTPClient fc = ftpClient.get();
        boolean flag = true;
        try {
            flag = fc.makeDirectory(dir);
            if (flag) {
                System.out.println("make Directory " + dir + " succeed");
            } else {
                System.out.println("make Directory " + dir + " false");
            }
        } catch (Exception e) {
            flag = false;
            ftpLog.error("在服务器上创建一个文件夹失败!!!", e);
        }
        
        return flag;
    }
}
